package com.itzdm.file.controller;

import com.itzdm.file.domain.dto.ChunkMergeDTO;
import com.itzdm.file.domain.dto.ChunkUploadDTO;
import com.itzdm.file.domain.po.SysFile;
import com.itzdm.file.domain.vo.FileVO;
import com.itzdm.file.service.ChunkUploadService;
import com.itzdm.file.service.FileService;
import com.itzdm.common.utils.MinioUtils;
import com.itzdm.common.exception.BadRequestException;
import com.itzdm.common.result.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @作者：张德明
 * @时间：2025/4/5 15:36
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class FileController {

    private final MinioUtils minioUtils;

    private final FileService fileService;

    private final ChunkUploadService chunkUploadService;

    /**
     * 下载文件
     *
     * @param fileUrl
     * @param response
     */
    @GetMapping("/download")
    public void downloadFile(@RequestParam String fileUrl, HttpServletResponse response) {
        try {
            // 提取文件路径和文件名
            String filePath = extractFilePath(fileUrl);
            String fileName = extractFileName(filePath);
            log.info("下载文件路径: {}", filePath);

            // 使用try-with-resources自动关闭流
            try (InputStream inputStream = minioUtils.downloadFile(filePath)) {
                setResponseHeaders(response, fileName);
                IOUtils.copy(inputStream, response.getOutputStream());
                response.flushBuffer();
            }
        } catch (IOException e) {
            log.error("文件下载失败: {}", e.getMessage());
            throw new BadRequestException("文件下载失败");
        }
    }

    // 提取文件路径
    private String extractFilePath(String fileUrl) {
        return fileUrl.substring(fileUrl.indexOf("talkflow/") + 9);
    }

    // 提取文件名
    private String extractFileName(String filePath) {
        return filePath.substring(filePath.lastIndexOf("/") + 1);
    }

    // 设置响应头
    private void setResponseHeaders(HttpServletResponse response, String fileName) {
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                String.format("attachment; filename=\"%s\"", fileName));
    }

    /**
     * 上传文件
     *
     * @param file
     * @return
     */
    @PostMapping("/uploadFile")
    public Result<FileVO> uploadFile(@RequestParam("file") MultipartFile file) {
        log.info("上传文件: {}", file.getOriginalFilename());
        FileVO fileVO = fileService.uploadFile(file);
        return Result.success(fileVO);
    }


    /**
     * 根据文件ID列表获取文件信息
     *
     * @param fileIds 文件ID列表
     * @return 文件信息列表
     */
    // feign调用
    @GetMapping("/getFileByIds")
    public List<SysFile> getFileByIds(@RequestParam("fileIds") List<Long> fileIds) {
        if (fileIds == null || fileIds.isEmpty()) {
            return List.of();
        }

        // 获取文件列表
        List<SysFile> listByIds = fileService.listByIds(fileIds);

        // 直接返回SysFile列表，不需要转换
        return listByIds;
    }


    /**
     * 上传文件分片
     *
     * @param file
     * @param fileHash
     * @param fileName
     * @param chunkIndex
     * @param totalChunks
     * @return
     */
    @PostMapping("/uploadChunk")
    public Result<Boolean> uploadChunk(
            @RequestParam("file") MultipartFile file,
            @RequestParam("fileHash") String fileHash,
            @RequestParam("fileName") String fileName,
            @RequestParam("chunkIndex") Integer chunkIndex,
            @RequestParam("totalChunks") Integer totalChunks
    ) {
        log.info("上传分片: fileName={}, fileHash={}, chunkIndex={}, totalChunks={}",
                fileName, fileHash, chunkIndex, totalChunks);
        ChunkUploadDTO chunkUploadDTO = new ChunkUploadDTO();
        chunkUploadDTO.setFile(file);
        chunkUploadDTO.setFileHash(fileHash);
        chunkUploadDTO.setFileName(fileName);
        chunkUploadDTO.setChunkIndex(chunkIndex);
        chunkUploadDTO.setTotalChunks(totalChunks);
        boolean uploadChunkResult = chunkUploadService.uploadChunk(chunkUploadDTO);
        return Result.success(uploadChunkResult);
    }

    /**
     * 检查文件分片是否已存在
     *
     * @param fileHash   文件哈希值
     * @param chunkIndex 分片索引
     * @return 检查结果
     */
    @GetMapping("/checkChunk")
    public Result<Boolean> checkChunk(
            @RequestParam("fileHash") String fileHash,
            @RequestParam("chunkIndex") Integer chunkIndex) {
        boolean exists = chunkUploadService.checkChunk(fileHash, chunkIndex);
        return Result.success(exists);
    }

    /**
     * 合并文件分片
     *
     * @param chunkMergeDTO 合并参数
     * @return 合并结果
     */
    @PostMapping("/mergeChunks")
    public Result<FileVO> mergeChunks(@RequestBody ChunkMergeDTO chunkMergeDTO) {
        log.info("合并分片: fileHash={}, fileName={}, totalChunks={}, isVideo={}",
                chunkMergeDTO.getFileHash(), chunkMergeDTO.getFileName(),
                chunkMergeDTO.getTotalChunks(), chunkMergeDTO.getIsVideo());

        FileVO fileVO = chunkUploadService.mergeChunks(chunkMergeDTO);
        if (fileVO == null) {
            return Result.error("合并分片失败");
        }
        return Result.success(fileVO);
    }
}
